library(tidyverse)
library(sf)
library(leaflet)

Originallyl, Leaflet is a javascript library. If yoy know your way around js it goes something like this:

##This is javascript code, DO NOT RUN!

var map = L.map('map').setView([51.505, -0.09], 13);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

L.marker([51.5, -0.09]).addTo(map)
    .bindPopup('A pretty CSS3 popup.<br> Easily customizable.')
    .openPopup();

You should also know to configure a CCS file in the header section of your html file and include Leaflet:

##This is html code, DO NOT RUN!

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css"
   integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
   crossorigin=""/>

     
 ##<!-- Make sure you put this AFTER Leaflet's CSS -->
 
     <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"
   integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og=="
   crossorigin=""> </script>

Fortunately, in the html widgets for R there is a Leaflet for R that let you use most of the capabilities of Leaflet with your regular R code. To create maps with leaflet you can use data.frame objects, sf objects, raster objects and json files.

Leaflet for R is methodologically easy to use and you can get farther by exploring the arguments of the functions. A nice feature of Leaflet is that is integrated with shiny.

1 Rudiments

To a create a leaflet object you only have to call the leaflet() function. If you have an object (think about an sf) which you want to plot you should pass it through the function as leaflet(YourObject). To add layers the %>% is used before a new function defining a new characteristic of the map. As a backgroung layer leaflet enables to use different maps providers with addProviderTiles.

leaflet() %>% 
  addProviderTiles(providers$Esri.NatGeoWorldMap)

You can see the Tiles options here. In the previous map you can zoom in and zoom out all aorund the world. You can set the specific view you want with the setView() function as in the following examples where the maps are centered in Plaza de la indepencia (Montevideo, Uruguay)

leaflet() %>% 
  addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 8)
leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16)

Of course, tha main benefit of using leaflet is getting your own data into the map. You can add a marker with addMarkers an specifying the long and lat coordinates.

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addMarkers(-56.199735, -34.906543)

An you can even assign a popup.

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addMarkers(-56.199735, -34.906543, popup = "Plaza Independencia")

An add many more markers.

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addMarkers(-56.199735, -34.906543, popup = "Plaza Independencia") %>% 
  addMarkers(-56.198309, -34.906563, popup = "Palacio Salvo")

#, -56.198309

It does not make sense to add geographic information one by one; rather, a better option is give to the function an object and atomatically plot all the markers.

Sites <- data.frame(longitud = c(-56.199735, -56.198309, -56.201037), 
                    lattitud = c(-34.906543, -34.906563, -34.907896), 
                    Name = c("Plaza Independencia", "Palacio Salvo", "Teatro Solis"))
leaflet(Sites) %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addMarkers(lng = ~longitud, lat = ~lattitud, popup = ~Name)

In the last example we configured our data in the leaflet() function, but is also possible to do it in the addMarkers() function.

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addMarkers(data = Sites, lng = ~longitud, lat = ~lattitud, popup = ~Name)

A marker can also be a circle:

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addCircleMarkers(data = Sites, lng = ~longitud, lat = ~lattitud)

But is time to plot more natural “geometric-vectorial” elements as a circle (addCircles())

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addCircles(data = Sites, lng = ~longitud, lat = ~lattitud,
                   radius = 100)

What is the difference among addCircleMarker() and addCircle().

2 Points

leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addCircles(data = Sites, lng = ~longitud, lat = ~lattitud,
                   radius = 100, opacity = 1, fillOpacity = 1)
leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -56.199735, lat = -34.906543, zoom = 16) %>% 
  addCircles(data = Sites, lng = ~longitud, lat = ~lattitud,
                   radius = 100, opacity = 1, fillOpacity = 0.7, color = "black", fillColor = "green")

3 Using our shapes

setwd("~/Dropbox/Teaching/SpatialAnalysis-MontevideoWorkshop2019/Notebooks/Montevideo_Data/Vectoriales_2011")
Uruguay <- st_read("ine_depto.shp")
setwd("~/Dropbox/Teaching/SpatialAnalysis-MontevideoWorkshop2019/Notebooks/Montevideo_Data/Accidentes2006-2010")
Accidents <- st_read("accidentes2006-2010.shp")
Uruguay = st_set_crs(Uruguay, 32721)
Accidents = st_set_crs(Accidents, 32721)
Uruguay <- st_transform(Uruguay,4326)
Accidents = st_transform(Accidents, 4326)
leaflet(Uruguay) %>% 
  addPolygons()
leaflet(Uruguay) %>% 
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons()
leaflet(Uruguay) %>% 
  addProviderTiles(providers$Stamen.Watercolor) %>% 
  addPolygons()
leaflet(Uruguay) %>% 
  addProviderTiles(providers$Stamen.Watercolor) %>% 
  addPolygons(color = "black", weight = 2, fillColor = "white")
leaflet(Uruguay) %>% 
  addProviderTiles(providers$Stamen.Watercolor) %>% 
  addPolygons(color = "black", weight = 2, fillColor = "white", fillOpacity = 1,
              highlightOptions = highlightOptions(color = "blue", fillColor = "blue", 
                                                  weight = 0, bringToFront = TRUE))
leaflet(Uruguay) %>% 
  addProviderTiles(providers$Stamen.Watercolor) %>% 
  addPolygons(color = "black", weight = 2, fillColor = "white", fillOpacity = 1,
              label = ~NOMBRE, labelOptions = labelOptions(
                style = list("font-weight" = "normal"), 
                textsize = "10px"),
              highlightOptions = highlightOptions(color = "blue", fillColor = "blue", 
                                                  weight = 0, bringToFront = TRUE))

Once you get used to leaflet you realize that is easy to create awosome maps. You may struggle a little bit with the inside function-arguments and probably will iterate a few times, but you will get it done.

#source: https://rstudio.github.io/leaflet/choropleths.html &
# From http://leafletjs.com/examples/choropleth/us-states.js
#install.packages("geojsonio")
#states <- geojsonio::geojson_read("json/us-states.geojson", what = "sp")
#see: https://github.com/rstudio/leaflet/issues/498
states <- geojsonio::geojson_read( 
        x = "https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json"
        , what = "sp"
    )
bins <- c(0, 10, 20, 50, 100, 200, 500, 1000, Inf)
pal <- colorBin("YlOrRd", domain = states$density, bins = bins)
labels <- sprintf(
  "<strong>%s</strong><br/>%g people / mi<sup>2</sup>",
  states$name, states$density
) %>% lapply(htmltools::HTML)
leaflet(states) %>%
  setView(-96, 37.8, 4) %>%
  addProviderTiles("MapBox", options = providerTileOptions(
    id = "mapbox.light",
    accessToken = Sys.getenv('MAPBOX_ACCESS_TOKEN'))) %>%
  addPolygons(
    fillColor = ~pal(density),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(pal = pal, values = ~density, opacity = 0.7, title = NULL,
    position = "bottomright")

4 Points

Accidents2009 <- Accidents %>% filter(ANIO == "2009")
leaflet(Accidents2009) %>% 
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addCircles()

5 Go Shiny!

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKYXV0aG9yOiAiT3JsYW5kbyBTYWJvZ2FsIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGxlYWZsZXQpCmBgYAoKT3JpZ2luYWxseWwsIExlYWZsZXQgaXMgYSBqYXZhc2NyaXB0IFtsaWJyYXJ5XShodHRwczovL2xlYWZsZXRqcy5jb20vKS4gSWYgeW95IGtub3cgeW91ciB3YXkgYXJvdW5kICoqanMqKiBpdCBnb2VzIHNvbWV0aGluZyBsaWtlIHRoaXM6IAoKYGBge3IsZXZhbD1GQUxTRX0KIyNUaGlzIGlzIGphdmFzY3JpcHQgY29kZSwgRE8gTk9UIFJVTiEKCnZhciBtYXAgPSBMLm1hcCgnbWFwJykuc2V0VmlldyhbNTEuNTA1LCAtMC4wOV0sIDEzKTsKCkwudGlsZUxheWVyKCdodHRwczovL3tzfS50aWxlLm9wZW5zdHJlZXRtYXAub3JnL3t6fS97eH0ve3l9LnBuZycsIHsKICAgIGF0dHJpYnV0aW9uOiAnJmNvcHk7IDxhIGhyZWY9Imh0dHBzOi8vd3d3Lm9wZW5zdHJlZXRtYXAub3JnL2NvcHlyaWdodCI+T3BlblN0cmVldE1hcDwvYT4gY29udHJpYnV0b3JzJwp9KS5hZGRUbyhtYXApOwoKTC5tYXJrZXIoWzUxLjUsIC0wLjA5XSkuYWRkVG8obWFwKQogICAgLmJpbmRQb3B1cCgnQSBwcmV0dHkgQ1NTMyBwb3B1cC48YnI+IEVhc2lseSBjdXN0b21pemFibGUuJykKICAgIC5vcGVuUG9wdXAoKTsKYGBgCgpZb3Ugc2hvdWxkIGFsc28ga25vdyB0byBjb25maWd1cmUgYSBDQ1MgZmlsZSBpbiB0aGUgaGVhZGVyIHNlY3Rpb24gb2YgeW91ciBodG1sIGZpbGUgYW5kIGluY2x1ZGUgTGVhZmxldDogCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyNUaGlzIGlzIGh0bWwgY29kZSwgRE8gTk9UIFJVTiEKCjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly91bnBrZy5jb20vbGVhZmxldEAxLjUuMS9kaXN0L2xlYWZsZXQuY3NzIgogICBpbnRlZ3JpdHk9InNoYTUxMi14d0UvQXo5enJqQklwaEFjQmIzRjZKVnF4ZjQ2K0NETHdmTE1IbG9OdTZLRVFDQVdpNkhjRFViZU9mQklwdEY3dGNDenVzS0ZqRncyeXV2RXBETDl3UT09IgogICBjcm9zc29yaWdpbj0iIi8+CgogICAgIAogIyM8IS0tIE1ha2Ugc3VyZSB5b3UgcHV0IHRoaXMgQUZURVIgTGVhZmxldCdzIENTUyAtLT4KIAogICAgIDxzY3JpcHQgc3JjPSJodHRwczovL3VucGtnLmNvbS9sZWFmbGV0QDEuNS4xL2Rpc3QvbGVhZmxldC5qcyIKICAgaW50ZWdyaXR5PSJzaGE1MTItR2ZmUE1GM1J2TWVZeWMxTFdNSHRLOEViUHYwaU5aOC9vVHRIUHg5L2NjMklMeFErdTkwNXFJd2RwVUxhcURreUJLZ09hQjU3UVRNZzd6dGc4Sm0yT2c9PSIKICAgY3Jvc3NvcmlnaW49IiI+IDwvc2NyaXB0PgoKYGBgCgpGb3J0dW5hdGVseSwgaW4gdGhlIFtodG1sIHdpZGdldHMgZm9yIFJdKGh0dHA6Ly93d3cuaHRtbHdpZGdldHMub3JnLykgdGhlcmUgaXMgYSBbTGVhZmxldCBmb3IgUl0oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9sZWFmbGV0LykgdGhhdCBsZXQgeW91IHVzZSBtb3N0IG9mIHRoZSBjYXBhYmlsaXRpZXMgb2YgTGVhZmxldCB3aXRoIHlvdXIgcmVndWxhciBSIGNvZGUuIFRvIGNyZWF0ZSBtYXBzIHdpdGggbGVhZmxldCB5b3UgY2FuIHVzZSAqZGF0YS5mcmFtZSogb2JqZWN0cywgKnNmKiBvYmplY3RzLCAqcmFzdGVyKiBvYmplY3RzIGFuZCAqanNvbiogZmlsZXMuIAoKTGVhZmxldCBmb3IgUiBpcyBtZXRob2RvbG9naWNhbGx5IGVhc3kgdG8gdXNlIGFuZCB5b3UgY2FuIGdldCBmYXJ0aGVyIGJ5IGV4cGxvcmluZyB0aGUgYXJndW1lbnRzIG9mIHRoZSBmdW5jdGlvbnMuIEEgbmljZSBmZWF0dXJlIG9mIExlYWZsZXQgaXMgdGhhdCBpcyBpbnRlZ3JhdGVkIHdpdGggc2hpbnkuIAoKI1J1ZGltZW50cwoKVG8gYSBjcmVhdGUgYSBsZWFmbGV0IG9iamVjdCB5b3Ugb25seSBoYXZlIHRvIGNhbGwgdGhlICoqbGVhZmxldCgpKiogZnVuY3Rpb24uIElmIHlvdSBoYXZlIGFuIG9iamVjdCAodGhpbmsgYWJvdXQgYW4gKnNmKikgd2hpY2ggeW91IHdhbnQgdG8gcGxvdCB5b3Ugc2hvdWxkIHBhc3MgaXQgdGhyb3VnaCB0aGUgZnVuY3Rpb24gYXMgKipsZWFmbGV0KFlvdXJPYmplY3QpKiouIFRvIGFkZCBsYXllcnMgdGhlICoqJT4lKiogaXMgdXNlZCBiZWZvcmUgYSBuZXcgZnVuY3Rpb24gZGVmaW5pbmcgYSBuZXcgY2hhcmFjdGVyaXN0aWMgb2YgdGhlIG1hcC4gCkFzIGEgYmFja2dyb3VuZyBsYXllciBsZWFmbGV0IGVuYWJsZXMgdG8gdXNlIGRpZmZlcmVudCBtYXBzIHByb3ZpZGVycyB3aXRoICoqYWRkUHJvdmlkZXJUaWxlcy4qKgoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkRXNyaS5OYXRHZW9Xb3JsZE1hcCkKYGBgCgpZb3UgY2FuIHNlZSB0aGUgVGlsZXMgb3B0aW9ucyBbaGVyZV0oaHR0cDovL2xlYWZsZXQtZXh0cmFzLmdpdGh1Yi5pby9sZWFmbGV0LXByb3ZpZGVycy9wcmV2aWV3LykuIApJbiB0aGUgcHJldmlvdXMgbWFwIHlvdSBjYW4gem9vbSBpbiBhbmQgem9vbSBvdXQgYWxsIGFvcnVuZCB0aGUgd29ybGQuIFlvdSBjYW4gc2V0IHRoZSBzcGVjaWZpYyB2aWV3IHlvdSB3YW50IHdpdGggdGhlICoqc2V0VmlldygpKiogZnVuY3Rpb24gYXMgaW4gdGhlIGZvbGxvd2luZyBleGFtcGxlcyB3aGVyZSB0aGUgbWFwcyBhcmUgY2VudGVyZWQgaW4gKlBsYXphIGRlIGxhIGluZGVwZW5jaWEqIChNb250ZXZpZGVvLCBVcnVndWF5KQoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkRXNyaS5OYXRHZW9Xb3JsZE1hcCkgJT4lCiAgc2V0VmlldyhsbmcgPSAtNTYuMTk5NzM1LCBsYXQgPSAtMzQuOTA2NTQzLCB6b29tID0gOCkKCmBgYAoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgc2V0VmlldyhsbmcgPSAtNTYuMTk5NzM1LCBsYXQgPSAtMzQuOTA2NTQzLCB6b29tID0gMTYpCmBgYAoKCgpPZiBjb3Vyc2UsIHRoYSBtYWluIGJlbmVmaXQgb2YgdXNpbmcgbGVhZmxldCBpcyBnZXR0aW5nIHlvdXIgb3duIGRhdGEgaW50byB0aGUgbWFwLiBZb3UgY2FuIGFkZCBhIG1hcmtlciB3aXRoICoqYWRkTWFya2VycyoqIGFuIHNwZWNpZnlpbmcgdGhlIGxvbmcgYW5kIGxhdCBjb29yZGluYXRlcy4gCgpgYGB7cn0KbGVhZmxldCgpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUKICBzZXRWaWV3KGxuZyA9IC01Ni4xOTk3MzUsIGxhdCA9IC0zNC45MDY1NDMsIHpvb20gPSAxNikgJT4lIAogIGFkZE1hcmtlcnMoLTU2LjE5OTczNSwgLTM0LjkwNjU0MykKYGBgCgpBbiB5b3UgY2FuIGV2ZW4gYXNzaWduIGEgcG9wdXAuCgpgYGB7cn0KbGVhZmxldCgpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUKICBzZXRWaWV3KGxuZyA9IC01Ni4xOTk3MzUsIGxhdCA9IC0zNC45MDY1NDMsIHpvb20gPSAxNikgJT4lIAogIGFkZE1hcmtlcnMoLTU2LjE5OTczNSwgLTM0LjkwNjU0MywgcG9wdXAgPSAiUGxhemEgSW5kZXBlbmRlbmNpYSIpCmBgYAoKQW4gYWRkIG1hbnkgbW9yZSBtYXJrZXJzLgoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgc2V0VmlldyhsbmcgPSAtNTYuMTk5NzM1LCBsYXQgPSAtMzQuOTA2NTQzLCB6b29tID0gMTYpICU+JSAKICBhZGRNYXJrZXJzKC01Ni4xOTk3MzUsIC0zNC45MDY1NDMsIHBvcHVwID0gIlBsYXphIEluZGVwZW5kZW5jaWEiKSAlPiUgCiAgYWRkTWFya2VycygtNTYuMTk4MzA5LCAtMzQuOTA2NTYzLCBwb3B1cCA9ICJQYWxhY2lvIFNhbHZvIikKYGBgCgoKSXQgZG9lcyBub3QgbWFrZSBzZW5zZSB0byBhZGQgZ2VvZ3JhcGhpYyBpbmZvcm1hdGlvbiBvbmUgYnkgb25lOyByYXRoZXIsIGEgYmV0dGVyIG9wdGlvbiBpcyBnaXZlIHRvIHRoZSBmdW5jdGlvbiBhbiBvYmplY3QgYW5kIGF0b21hdGljYWxseSBwbG90IGFsbCB0aGUgbWFya2Vycy4KCmBgYHtyfQpTaXRlcyA8LSBkYXRhLmZyYW1lKGxvbmdpdHVkID0gYygtNTYuMTk5NzM1LCAtNTYuMTk4MzA5LCAtNTYuMjAxMDM3KSwgCiAgICAgICAgICAgICAgICAgICAgbGF0dGl0dWQgPSBjKC0zNC45MDY1NDMsIC0zNC45MDY1NjMsIC0zNC45MDc4OTYpLCAKICAgICAgICAgICAgICAgICAgICBOYW1lID0gYygiUGxhemEgSW5kZXBlbmRlbmNpYSIsICJQYWxhY2lvIFNhbHZvIiwgIlRlYXRybyBTb2xpcyIpKQoKbGVhZmxldChTaXRlcykgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQogIHNldFZpZXcobG5nID0gLTU2LjE5OTczNSwgbGF0ID0gLTM0LjkwNjU0Mywgem9vbSA9IDE2KSAlPiUgCiAgYWRkTWFya2VycyhsbmcgPSB+bG9uZ2l0dWQsIGxhdCA9IH5sYXR0aXR1ZCwgcG9wdXAgPSB+TmFtZSkKYGBgCgpJbiB0aGUgbGFzdCBleGFtcGxlIHdlIGNvbmZpZ3VyZWQgb3VyIGRhdGEgaW4gdGhlICoqbGVhZmxldCgpKiogZnVuY3Rpb24sIGJ1dCBpcyBhbHNvIHBvc3NpYmxlIHRvIGRvIGl0IGluIHRoZSAqKmFkZE1hcmtlcnMoKSoqIGZ1bmN0aW9uLgoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgc2V0VmlldyhsbmcgPSAtNTYuMTk5NzM1LCBsYXQgPSAtMzQuOTA2NTQzLCB6b29tID0gMTYpICU+JSAKICBhZGRNYXJrZXJzKGRhdGEgPSBTaXRlcywgbG5nID0gfmxvbmdpdHVkLCBsYXQgPSB+bGF0dGl0dWQsIHBvcHVwID0gfk5hbWUpCmBgYAoKCkEgbWFya2VyIGNhbiBhbHNvIGJlIGEgY2lyY2xlOgoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgc2V0VmlldyhsbmcgPSAtNTYuMTk5NzM1LCBsYXQgPSAtMzQuOTA2NTQzLCB6b29tID0gMTYpICU+JSAKICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBTaXRlcywgbG5nID0gfmxvbmdpdHVkLCBsYXQgPSB+bGF0dGl0dWQpCmBgYAoKCkJ1dCBpcyB0aW1lIHRvIHBsb3QgbW9yZSBuYXR1cmFsICJnZW9tZXRyaWMtdmVjdG9yaWFsIiBlbGVtZW50cyBhcyBhIGNpcmNsZSAoKiphZGRDaXJjbGVzKCkqKikKCmBgYHtyfQpsZWFmbGV0KCkgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQogIHNldFZpZXcobG5nID0gLTU2LjE5OTczNSwgbGF0ID0gLTM0LjkwNjU0Mywgem9vbSA9IDE2KSAlPiUgCiAgYWRkQ2lyY2xlcyhkYXRhID0gU2l0ZXMsIGxuZyA9IH5sb25naXR1ZCwgbGF0ID0gfmxhdHRpdHVkLAogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gMTAwKQpgYGAKCgpXaGF0IGlzIHRoZSBkaWZmZXJlbmNlIGFtb25nICoqYWRkQ2lyY2xlTWFya2VyKCkqKiBhbmQgKiphZGRDaXJjbGUoKS4qKgoKCiNQb2ludHMKCgpgYGB7cn0KbGVhZmxldCgpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUKICBzZXRWaWV3KGxuZyA9IC01Ni4xOTk3MzUsIGxhdCA9IC0zNC45MDY1NDMsIHpvb20gPSAxNikgJT4lIAogIGFkZENpcmNsZXMoZGF0YSA9IFNpdGVzLCBsbmcgPSB+bG9uZ2l0dWQsIGxhdCA9IH5sYXR0aXR1ZCwKICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDEwMCwgb3BhY2l0eSA9IDEsIGZpbGxPcGFjaXR5ID0gMSkKYGBgCgoKYGBge3J9CmxlYWZsZXQoKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgc2V0VmlldyhsbmcgPSAtNTYuMTk5NzM1LCBsYXQgPSAtMzQuOTA2NTQzLCB6b29tID0gMTYpICU+JSAKICBhZGRDaXJjbGVzKGRhdGEgPSBTaXRlcywgbG5nID0gfmxvbmdpdHVkLCBsYXQgPSB+bGF0dGl0dWQsCiAgICAgICAgICAgICAgICAgICByYWRpdXMgPSAxMDAsIG9wYWNpdHkgPSAxLCBmaWxsT3BhY2l0eSA9IDAuNywgY29sb3IgPSAiYmxhY2siLCBmaWxsQ29sb3IgPSAiZ3JlZW4iKQpgYGAKCgoKI1VzaW5nIG91ciBzaGFwZXMKCmBgYHtyfQpzZXR3ZCgifi9Ecm9wYm94L1RlYWNoaW5nL1NwYXRpYWxBbmFseXNpcy1Nb250ZXZpZGVvV29ya3Nob3AyMDE5L05vdGVib29rcy9Nb250ZXZpZGVvX0RhdGEvVmVjdG9yaWFsZXNfMjAxMSIpClVydWd1YXkgPC0gc3RfcmVhZCgiaW5lX2RlcHRvLnNocCIpCmBgYAoKYGBge3J9CnNldHdkKCJ+L0Ryb3Bib3gvVGVhY2hpbmcvU3BhdGlhbEFuYWx5c2lzLU1vbnRldmlkZW9Xb3Jrc2hvcDIwMTkvTm90ZWJvb2tzL01vbnRldmlkZW9fRGF0YS9BY2NpZGVudGVzMjAwNi0yMDEwIikKQWNjaWRlbnRzIDwtIHN0X3JlYWQoImFjY2lkZW50ZXMyMDA2LTIwMTAuc2hwIikKYGBgCgpgYGB7cn0KVXJ1Z3VheSA9IHN0X3NldF9jcnMoVXJ1Z3VheSwgMzI3MjEpCkFjY2lkZW50cyA9IHN0X3NldF9jcnMoQWNjaWRlbnRzLCAzMjcyMSkKClVydWd1YXkgPC0gc3RfdHJhbnNmb3JtKFVydWd1YXksNDMyNikKQWNjaWRlbnRzID0gc3RfdHJhbnNmb3JtKEFjY2lkZW50cywgNDMyNikKYGBgCgpgYGB7cn0KbGVhZmxldChVcnVndWF5KSAlPiUgCiAgYWRkUG9seWdvbnMoKQpgYGAKCgpgYGB7cn0KbGVhZmxldChVcnVndWF5KSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lIAogIGFkZFBvbHlnb25zKCkKYGBgCgpgYGB7cn0KbGVhZmxldChVcnVndWF5KSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkU3RhbWVuLldhdGVyY29sb3IpICU+JSAKICBhZGRQb2x5Z29ucygpCmBgYAoKCmBgYHtyfQpsZWFmbGV0KFVydWd1YXkpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRTdGFtZW4uV2F0ZXJjb2xvcikgJT4lIAogIGFkZFBvbHlnb25zKGNvbG9yID0gImJsYWNrIiwgd2VpZ2h0ID0gMiwgZmlsbENvbG9yID0gIndoaXRlIikKYGBgCgoKYGBge3J9CmxlYWZsZXQoVXJ1Z3VheSkgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJFN0YW1lbi5XYXRlcmNvbG9yKSAlPiUgCiAgYWRkUG9seWdvbnMoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAyLCBmaWxsQ29sb3IgPSAid2hpdGUiLCBmaWxsT3BhY2l0eSA9IDEsCiAgICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiYmx1ZSIsIGZpbGxDb2xvciA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMCwgYnJpbmdUb0Zyb250ID0gVFJVRSkpCmBgYAoKYGBge3J9CmxlYWZsZXQoVXJ1Z3VheSkgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJFN0YW1lbi5XYXRlcmNvbG9yKSAlPiUgCiAgYWRkUG9seWdvbnMoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAyLCBmaWxsQ29sb3IgPSAid2hpdGUiLCBmaWxsT3BhY2l0eSA9IDEsCiAgICAgICAgICAgICAgbGFiZWwgPSB+Tk9NQlJFLCBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoCiAgICAgICAgICAgICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiKSwgCiAgICAgICAgICAgICAgICB0ZXh0c2l6ZSA9ICIxMHB4IiksCiAgICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiYmx1ZSIsIGZpbGxDb2xvciA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMCwgYnJpbmdUb0Zyb250ID0gVFJVRSkpCmBgYAoKCk9uY2UgeW91IGdldCB1c2VkIHRvIGxlYWZsZXQgeW91IHJlYWxpemUgdGhhdCBpcyBlYXN5IHRvIGNyZWF0ZSBhd29zb21lIG1hcHMuIFlvdSBtYXkgc3RydWdnbGUgYSBsaXR0bGUgYml0IHdpdGggdGhlIGluc2lkZSBmdW5jdGlvbi1hcmd1bWVudHMgYW5kIHByb2JhYmx5IHdpbGwgaXRlcmF0ZSBhIGZldyB0aW1lcywgYnV0IHlvdSB3aWxsIGdldCBpdCBkb25lLiAKCmBgYHtyfQojc291cmNlOiBodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvY2hvcm9wbGV0aHMuaHRtbCAmCiMgRnJvbSBodHRwOi8vbGVhZmxldGpzLmNvbS9leGFtcGxlcy9jaG9yb3BsZXRoL3VzLXN0YXRlcy5qcwoKI2luc3RhbGwucGFja2FnZXMoImdlb2pzb25pbyIpCgojc3RhdGVzIDwtIGdlb2pzb25pbzo6Z2VvanNvbl9yZWFkKCJqc29uL3VzLXN0YXRlcy5nZW9qc29uIiwgd2hhdCA9ICJzcCIpCiNzZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2xlYWZsZXQvaXNzdWVzLzQ5OAoKc3RhdGVzIDwtIGdlb2pzb25pbzo6Z2VvanNvbl9yZWFkKCAKICAgICAgICB4ID0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9QdWJsaWNhTXVuZGkvTWFwcGluZ0FQSS9tYXN0ZXIvZGF0YS9nZW9qc29uL3VzLXN0YXRlcy5qc29uIgogICAgICAgICwgd2hhdCA9ICJzcCIKICAgICkKCgpiaW5zIDwtIGMoMCwgMTAsIDIwLCA1MCwgMTAwLCAyMDAsIDUwMCwgMTAwMCwgSW5mKQpwYWwgPC0gY29sb3JCaW4oIllsT3JSZCIsIGRvbWFpbiA9IHN0YXRlcyRkZW5zaXR5LCBiaW5zID0gYmlucykKCmxhYmVscyA8LSBzcHJpbnRmKAogICI8c3Ryb25nPiVzPC9zdHJvbmc+PGJyLz4lZyBwZW9wbGUgLyBtaTxzdXA+Mjwvc3VwPiIsCiAgc3RhdGVzJG5hbWUsIHN0YXRlcyRkZW5zaXR5CikgJT4lIGxhcHBseShodG1sdG9vbHM6OkhUTUwpCgpsZWFmbGV0KHN0YXRlcykgJT4lCiAgc2V0VmlldygtOTYsIDM3LjgsIDQpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIk1hcEJveCIsIG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKAogICAgaWQgPSAibWFwYm94LmxpZ2h0IiwKICAgIGFjY2Vzc1Rva2VuID0gU3lzLmdldGVudignTUFQQk9YX0FDQ0VTU19UT0tFTicpKSkgJT4lCiAgYWRkUG9seWdvbnMoCiAgICBmaWxsQ29sb3IgPSB+cGFsKGRlbnNpdHkpLAogICAgd2VpZ2h0ID0gMiwKICAgIG9wYWNpdHkgPSAxLAogICAgY29sb3IgPSAid2hpdGUiLAogICAgZGFzaEFycmF5ID0gIjMiLAogICAgZmlsbE9wYWNpdHkgPSAwLjcsCiAgICBoaWdobGlnaHQgPSBoaWdobGlnaHRPcHRpb25zKAogICAgICB3ZWlnaHQgPSA1LAogICAgICBjb2xvciA9ICIjNjY2IiwKICAgICAgZGFzaEFycmF5ID0gIiIsCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LAogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwKICAgIGxhYmVsID0gbGFiZWxzLAogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKAogICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwKICAgICAgdGV4dHNpemUgPSAiMTVweCIsCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5kZW5zaXR5LCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsCiAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIpCgoKYGBgCgoKCiNQb2ludHMKCmBgYHtyfQpBY2NpZGVudHMyMDA5IDwtIEFjY2lkZW50cyAlPiUgZmlsdGVyKEFOSU8gPT0gIjIwMDkiKQpsZWFmbGV0KEFjY2lkZW50czIwMDkpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUgCiAgYWRkQ2lyY2xlcygpCmBgYAoKCgojR28gU2hpbnkhCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCg==